let activeEffect
let effectStack = []
/**
 * 关于依赖
 * 从数据的角度,依赖是指依赖该属性的[副作用函数]
 */
function cleanup(effectFn) {
    for (let i = 0; i < effectFn.deps.length; i++) {
        effectFn.deps[i].delete(effectFn)
    }
    effectFn.deps.length = 0
}
function effect(fn) {
    effectFn = () => {
        console.log('effectFn executed')
        cleanup(effectFn)
        activeEffect = effectFn
        effectStack.push(effectFn)
        fn()
        effectStack.pop()
        activeEffect = effectStack[effectStack.length - 1]
    }
    effectFn.deps = []
    effectFn()
}

/**
 * 副作用函数中被读取的数据必须被代理
 */
function proxyData(data) {
    let bucket = new WeakMap()
    function track(target, key) {
        if (!activeEffect) return target[key]
        let depsMap = bucket.get(target)
        if (!depsMap) {
            bucket.set(target, depsMap = new Map())
        }
        let deps = depsMap.get(key)
        if (!deps) {
            depsMap.set(key, deps = new Set())
        }
        deps.add(activeEffect)
        activeEffect.deps.push(deps)
    }

    function trigger(target, key) {
        let depsMap = bucket.get(target)
        if (!depsMap) {
            return
        }
        const effects = depsMap.get(key)
        let effectsToRun = new Set()
        effects && effects.forEach(effectFn => {
            if (effectFn != activeEffect) {
                effectsToRun.add(effectFn)
            }
        })
        effectsToRun.forEach(effectFn => effectFn())
    }
    return new Proxy(data, {
        get(target, key) {
            track(target, key)
            return target[key]
        },
        set(target, key, newVal) {
            target[key] = newVal
            trigger(target, key)
        }
    })
}


//test code


// 原始数据
const data = { foo: true, bar: true }
// 代理对象
const obj = proxyData(data)

// 全局变量
let temp1, temp2

// effectFn1 嵌套了 effectFn2
effect(function effectFn1() {
    console.log('effectFn1 执行')

    effect(function effectFn2() {
        console.log('effectFn2 执行')
        // 在 effectFn2 中读取 obj.bar 属性
        temp2 = obj.bar
    })
    // 在 effectFn1 中读取 obj.foo 属性
    temp1 = obj.foo
})

obj.foo = "gaga"

